package me.caofeng.interceptor;

import me.caofeng.annotation.MediaType;
import me.caofeng.enums.MediaTypes;
import me.caofeng.enums.ResponseCode;
import me.caofeng.pojo.Response;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartRequest;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Iterator;
import java.util.Optional;

/**
 * Copyright © 2017曹峰. All rights reserved.
 *
 * @Prject: mall
 * @Package: me.caofeng.interceptor
 * @Description: 上传文件类型拦截器，配和 {@link me.caofeng.enums.MediaTypes} 控制上传文件类型
 * @Author: 曹峰 blog.caofeng.me
 * @Date: 2017-06-21 11:11
 * @Version: V1.0
 */
public class MediaTypeInterceptor implements HandlerInterceptor {
    private static Logger LOGGER = LogManager.getLogger(MediaTypeInterceptor.class);

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        if (!(request instanceof MultipartRequest)) {
            Response.response(ResponseCode.ILLEGAL_ARGUMENT, response, "服务器错误，暂时不能上传文件", null);
            return false;
        }

        MediaTypes mediaTypes = extraMediaTypes((HandlerMethod) handler);

        if (null == mediaTypes) {
            Response.response(ResponseCode.ILLEGAL_ARGUMENT, response, "服务器错误，暂时不能上传文件", null);
            return false;
        }

        if (filterMultipartRequest((MultipartRequest) request, mediaTypes)) {
            return true;
        } else {
            Response.response(ResponseCode.ILLEGAL_ARGUMENT, response, "非法文件类型，请上传正确的文件", null);
            return false;
        }

    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }

    private boolean checkFile(MultipartFile multipartFile,MediaTypes mediaTypes) {

        if (!MediaTypes.isMatched(mediaTypes,multipartFile.getContentType())){
            return true;
        }

        if (multipartFile.getSize() >= 5242880) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * @Author:曹峰 blog.caofeng.me
     * @Date: 2017/6/21 15:02
     * @Description: 从注解中取出允许上传的文件类型
     */
    private MediaTypes extraMediaTypes(HandlerMethod method) {
        MediaTypes mediaTypes = null;
        MediaType mediaType = method.getMethodAnnotation(MediaType.class);

        if (null != mediaType) {
            mediaTypes = mediaType.value();
        }

        return mediaTypes;
    }

    /**
     * @Author:曹峰 blog.caofeng.me
     * @Date: 2017/7/4 9:19
     * @Description: 对文件类型及文件大小进行过滤
    */
    private boolean filterMultipartRequest(MultipartRequest request, MediaTypes mediaTypes) {
        MultipartRequest multipartRequest = request;

        Iterator<String> keys = multipartRequest.getFileNames();

        if (!keys.hasNext()) {
            return false;
        }

        while (keys.hasNext()) {
            String key = keys.next();
            Optional<MultipartFile> file = multipartRequest.getFiles(key)
                    .stream()
                    .filter(multipartFile -> checkFile(multipartFile,mediaTypes)).findFirst();

            if (file.isPresent()){
                return false;
            }
        }

        return true;
    }


}
